#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
安全模块 - 用于验证和保护连接
"""

import socket
import ipaddress
from typing import Tuple, List, Optional
from config import load_config
from logger import setup_logger

logger = setup_logger("security")

def is_ip_allowed(client_ip: str) -> bool:
    """
    检查IP是否被允许连接
    
    Args:
        client_ip: 客户端IP地址
        
    Returns:
        bool: 如果允许连接返回True，否则返回False
    """
    config = load_config()
    security_config = config.get("security", {})
    
    # 检查黑名单
    blacklist = security_config.get("blacklist_ips", [])
    for ip_pattern in blacklist:
        try:
            if "/" in ip_pattern:  # CIDR格式
                if ipaddress.ip_address(client_ip) in ipaddress.ip_network(ip_pattern):
                    logger.warning(f"拒绝来自黑名单IP的连接: {client_ip}")
                    return False
            elif ip_pattern == client_ip:  # 精确匹配
                logger.warning(f"拒绝来自黑名单IP的连接: {client_ip}")
                return False
        except ValueError:
            continue
    
    # 检查白名单
    allowed_ips = security_config.get("allowed_ips", [])
    if not allowed_ips:  # 空白名单表示允许所有IP
        return True
    
    # 如果有白名单，检查是否在白名单中
    for ip_pattern in allowed_ips:
        try:
            if "/" in ip_pattern:  # CIDR格式
                if ipaddress.ip_address(client_ip) in ipaddress.ip_network(ip_pattern):
                    return True
            elif ip_pattern == client_ip:  # 精确匹配
                return True
        except ValueError:
            continue
    
    logger.warning(f"拒绝未授权IP的连接: {client_ip}")
    return False

def validate_port(port: int) -> bool:
    """
    验证端口号是否有效
    
    Args:
        port: 端口号
        
    Returns:
        bool: 如果端口有效返回True，否则返回False
    """
    return 0 < port < 65536

def validate_host(host: str) -> bool:
    """
    验证主机名是否有效
    
    Args:
        host: 主机名或IP地址
        
    Returns:
        bool: 如果主机名有效返回True，否则返回False
    """
    try:
        socket.gethostbyname(host)
        return True
    except socket.error:
        return False